﻿using Basic.Oss.Interfaces;
using Basic.Oss.Options;
using Microsoft.Extensions.Options;
using Shared.Const.Enum.Oss;

namespace Basic.Oss.Implements;

/// <summary>
/// 阿里云OSS对象存储客户端
/// </summary>
public class AliOssClient : IAliOssClient
{
    private readonly OssClient _ossClient;
    private readonly IOptions<AliOssOptions> _options;

    public AliOssClient(IOptions<AliOssOptions> options)
    {
        _options = options;
        var op = _options.Value;
        _ossClient = new OssClient(op.Endpoint, op.AccessKeyId, op.AccessKeySecret);
    }

    ///<inheritdoc/>
    public PutObjectResult PutObjectCommon(string objectName, byte[] content, string bucketName = OssConstData.DefaultBucketName)
    {
        using var ms = new MemoryStream(content);
        return _ossClient.PutObject(bucketName, objectName, ms);
    }

    ///<inheritdoc/>
    public string PutObjectSignature(string objectName, byte[] content, string bucketName = OssConstData.DefaultBucketName)
    {
        var generatePresignedUriRequest = new GeneratePresignedUriRequest(bucketName, objectName, SignHttpMethod.Put);
        var signedUrl = _ossClient.GeneratePresignedUri(generatePresignedUriRequest);
        using var ms = new MemoryStream(content);
        _ossClient.PutObject(signedUrl, ms);
        return signedUrl.ToString();
    }

    ///<inheritdoc/>
    public string GetSignatureUrl(string objectName, string bucketName = OssConstData.DefaultBucketName)
    {
        var request = new GeneratePresignedUriRequest(bucketName, objectName, SignHttpMethod.Get);
        //设置过期时间
        request.Expiration = DateTime.Now.AddYears(99);
        var signedUrl = _ossClient.GeneratePresignedUri(request);
        return signedUrl.ToString();
    }

    ///<inheritdoc/>
    public async Task<byte[]> DownloadFile(string objectName, string bucketName = OssConstData.DefaultBucketName)
    {
        objectName = GetOssFileName(objectName, EnumOssDir.FileDir);
        var obj = _ossClient.GetObject(bucketName, objectName);
        if (obj == null || obj.Content == null || obj.Content.Length == 0)
            return new byte[0];

        using Stream stream = obj.Content;
        using MemoryStream ms = new MemoryStream();
        await stream.CopyToAsync(ms);
        if (ms.CanSeek) ms.Seek(0, SeekOrigin.Begin);
        return ms.ToArray();
    }

    ///<inheritdoc/>
    public bool DeleteFile(string objectName, string bucketName = OssConstData.DefaultBucketName)
    {
        objectName = GetOssFileName(objectName, EnumOssDir.FileDir);
        // 删除文件。
        var res = _ossClient.DeleteObject(bucketName, objectName);
        return res != null && res.HttpStatusCode == System.Net.HttpStatusCode.NoContent;
    }

    public string GetOssFileName(string filename, EnumOssDir dir = EnumOssDir.RootDir)
    {
        return dir == EnumOssDir.RootDir ? filename : $"{dir.GetEnumItem().TextName}/{filename}";
    }


    #region Stream

    ///<inheritdoc/>
    public PutObjectResult PutObjectStream(string objectName, Stream content, string bucketName = OssConstData.DefaultBucketName)
    {
        if (content.CanSeek)
            content.Seek(0, SeekOrigin.Begin);
        var resp = _ossClient.PutObject(bucketName, objectName, content);
        return resp;
    }

    ///<inheritdoc/>
    public string PutObjectSignature(string objectName, Stream content, string bucketName = OssConstData.DefaultBucketName)
    {
        var generatePresignedUriRequest = new GeneratePresignedUriRequest(bucketName, objectName, SignHttpMethod.Put);
        var signedUrl = _ossClient.GeneratePresignedUri(generatePresignedUriRequest);
        content.Seek(0, SeekOrigin.Begin);
        _ossClient.PutObject(signedUrl, content);
        return signedUrl.ToString();
    }

    ///<inheritdoc/>
    public async Task<Stream> DownloadFileStream(string objectName, string bucketName = OssConstData.DefaultBucketName)
    {
        objectName = GetOssFileName(objectName, EnumOssDir.FileDir);
        var obj = _ossClient.GetObject(bucketName, objectName);
        if (obj == null)
            return null;

        using Stream stream = obj.Content;
        MemoryStream ms = new MemoryStream();
        await stream.CopyToAsync(ms);
        if (ms.CanSeek) ms.Seek(0, SeekOrigin.Begin);
        return ms;
    }

    #endregion

}